"""热点数据模型
定义统一的数据格式
"""
from typing import Optional, List, Dict, Any
from datetime import datetime
from pydantic import BaseModel, Field, validator
from enum import Enum


class Platform(str, Enum):
    """平台枚举"""
    WEIBO = "weibo"
    ZHIHU = "zhihu"
    BAIDU = "baidu"
    DOUYIN = "douyin"
    BILIBILI = "bilibili"
    TOUTIAO = "toutiao"
    XIAOHONGSHU = "xiaohongshu"
    REDDIT = "reddit"
    TWITTER = "twitter"
    YOUTUBE = "youtube"


class HotItemStatus(str, Enum):
    """热点状态"""
    RISING = "rising"  # 上升
    HOT = "hot"  # 热门
    NEW = "new"  # 新话题
    EXPLOSIVE = "explosive"  # 爆炸性
    CONTROVERSIAL = "controversial"  # 争议性


class HotItem(BaseModel):
    """热点数据模型"""
    
    # 基础字段
    data_id: str = Field(..., description="数据唯一ID")
    platform: Platform = Field(..., description="平台")
    rank: Optional[int] = Field(None, description="排名")
    title: str = Field(..., description="标题")
    url: Optional[str] = Field(None, description="链接")
    
    # 热度指标
    hot_value: Optional[int] = Field(None, description="热度值")
    hot_level: Optional[str] = Field(None, description="热度等级")
    status: Optional[HotItemStatus] = Field(None, description="状态")
    
    # 内容相关
    content: Optional[str] = Field(None, description="内容")
    summary: Optional[str] = Field(None, description="摘要")
    category: Optional[str] = Field(None, description="分类")
    tags: List[str] = Field(default_factory=list, description="标签")
    keywords: List[str] = Field(default_factory=list, description="关键词")
    
    # 作者信息
    author: Optional[str] = Field(None, description="作者")
    author_id: Optional[str] = Field(None, description="作者ID")
    author_url: Optional[str] = Field(None, description="作者主页")
    
    # 互动数据
    view_count: Optional[int] = Field(None, description="浏览量")
    comment_count: Optional[int] = Field(None, description="评论数")
    like_count: Optional[int] = Field(None, description="点赞数")
    share_count: Optional[int] = Field(None, description="分享数")
    collect_count: Optional[int] = Field(None, description="收藏数")
    
    # 媒体信息
    image_url: Optional[str] = Field(None, description="图片URL")
    video_url: Optional[str] = Field(None, description="视频URL")
    media_urls: List[str] = Field(default_factory=list, description="媒体URL列表")
    
    # 时间信息
    publish_time: Optional[datetime] = Field(None, description="发布时间")
    crawled_at: datetime = Field(default_factory=datetime.now, description="爬取时间")
    updated_at: Optional[datetime] = Field(None, description="更新时间")
    
    # 扩展信息
    extra_data: Dict[str, Any] = Field(default_factory=dict, description="额外数据")
    raw_data: Optional[Dict[str, Any]] = Field(None, description="原始数据")
    
    class Config:
        """模型配置"""
        use_enum_values = True
        json_encoders = {
            datetime: lambda v: v.isoformat() if v else None
        }
    
    @validator('url', 'author_url', 'image_url', 'video_url')
    def validate_url(cls, v):
        """验证URL格式"""
        if v and not v.startswith(('http://', 'https://', '//')):
            # 尝试修复相对URL
            if v.startswith('/'):
                return v  # 保留相对URL，后续处理时补全
            return f"https://{v}"
        return v
    
    @validator('hot_value')
    def validate_hot_value(cls, v):
        """验证热度值"""
        if v is not None and v < 0:
            return 0
        return v
    
    def to_dict(self, exclude_none: bool = True, exclude_raw: bool = True) -> Dict[str, Any]:
        """转换为字典
        
        Args:
            exclude_none: 是否排除None值
            exclude_raw: 是否排除原始数据
            
        Returns:
            字典格式的数据
        """
        data = self.dict(exclude_none=exclude_none)
        
        if exclude_raw and 'raw_data' in data:
            del data['raw_data']
        
        return data
    
    def calculate_score(self) -> float:
        """计算综合得分
        
        Returns:
            综合得分
        """
        score = 0.0
        
        # 基于排名的分数（排名越靠前分数越高）
        if self.rank:
            score += max(0, 100 - self.rank)
        
        # 基于互动数据的分数
        if self.view_count:
            score += min(self.view_count / 10000, 100)  # 每万次浏览加分，最多100分
        
        if self.comment_count:
            score += min(self.comment_count / 100, 50)  # 每百条评论加分，最多50分
        
        if self.like_count:
            score += min(self.like_count / 1000, 50)  # 每千个赞加分，最多50分
        
        # 基于状态的加分
        if self.status == HotItemStatus.EXPLOSIVE:
            score *= 1.5
        elif self.status == HotItemStatus.RISING:
            score *= 1.2
        elif self.status == HotItemStatus.CONTROVERSIAL:
            score *= 1.1
        
        return round(score, 2)
    
    def is_valid(self) -> bool:
        """检查数据是否有效
        
        Returns:
            是否有效
        """
        # 必须有标题
        if not self.title or len(self.title.strip()) == 0:
            return False
        
        # 标题长度检查
        if len(self.title) < 2 or len(self.title) > 500:
            return False
        
        # 至少有一个有效的指标
        has_metrics = any([
            self.hot_value,
            self.view_count,
            self.comment_count,
            self.like_count
        ])
        
        return has_metrics or self.rank is not None
    
    def merge(self, other: 'HotItem') -> 'HotItem':
        """合并另一个HotItem的数据
        
        Args:
            other: 另一个HotItem实例
            
        Returns:
            合并后的新实例
        """
        if self.data_id != other.data_id:
            raise ValueError("Cannot merge items with different data_id")
        
        # 创建新实例
        merged_data = self.dict()
        
        # 更新非空字段
        for field, value in other.dict().items():
            if value is not None and field != 'data_id':
                if field in ['tags', 'keywords', 'media_urls']:
                    # 合并列表字段
                    merged_data[field] = list(set(merged_data.get(field, []) + value))
                elif field == 'extra_data':
                    # 合并字典字段
                    merged_data[field].update(value)
                elif field in ['view_count', 'comment_count', 'like_count', 'share_count']:
                    # 取最大值
                    current = merged_data.get(field, 0) or 0
                    merged_data[field] = max(current, value)
                else:
                    # 覆盖更新
                    merged_data[field] = value
        
        # 更新时间
        merged_data['updated_at'] = datetime.now()
        
        return HotItem(**merged_data)


class HotItemBatch(BaseModel):
    """热点数据批次"""
    
    platform: Platform = Field(..., description="平台")
    items: List[HotItem] = Field(default_factory=list, description="热点列表")
    total_count: int = Field(0, description="总数")
    crawled_at: datetime = Field(default_factory=datetime.now, description="爬取时间")
    metadata: Dict[str, Any] = Field(default_factory=dict, description="元数据")
    
    def add_item(self, item: HotItem):
        """添加热点项
        
        Args:
            item: 热点项
        """
        if item.platform != self.platform:
            raise ValueError(f"Item platform {item.platform} doesn't match batch platform {self.platform}")
        
        self.items.append(item)
        self.total_count = len(self.items)
    
    def get_top_items(self, n: int = 10) -> List[HotItem]:
        """获取前N个热点
        
        Args:
            n: 数量
            
        Returns:
            热点列表
        """
        # 先按排名排序，没有排名的按得分排序
        sorted_items = sorted(
            self.items,
            key=lambda x: (x.rank or 999, -x.calculate_score())
        )
        return sorted_items[:n]
    
    def filter_by_status(self, status: HotItemStatus) -> List[HotItem]:
        """按状态筛选
        
        Args:
            status: 状态
            
        Returns:
            筛选后的列表
        """
        return [item for item in self.items if item.status == status]
    
    def to_dict(self, exclude_none: bool = True) -> Dict[str, Any]:
        """转换为字典
        
        Args:
            exclude_none: 是否排除None值
            
        Returns:
            字典格式的数据
        """
        return {
            'platform': self.platform,
            'items': [item.to_dict(exclude_none) for item in self.items],
            'total_count': self.total_count,
            'crawled_at': self.crawled_at.isoformat(),
            'metadata': self.metadata
        }